package org.vgou.dao.impl;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.orm.hibernate3.HibernateAccessor;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.vgou.util.Page;

/**
* 
* Copyright (c) 2011, vgou<br>
* All rights reserved.<br>
* 
* @since 2011-11-27
* @author <a href="mailto:jason.hxx@gmail.com">jason</a>
* @version Id: AbstractManager.java 
* @comment	封装HIBERNATE访问接口公共类
* 
*/
public abstract class AbstractManager<T> extends HibernateDaoSupport {
	protected static int DEFAULT_BATCH_SIZE = 50;

	/**
	 * save the object of entity
	 * 
	 * @param entity
	 */
	public Object save(final Object entity) throws DataAccessException {
		try {
			return getHibernateTemplate().save(entity);
		} catch (DataAccessException e) {
			logger.error("存储对象出错:" + e.getMessage());
			throw e;
		}
	}

	public void saveOrUpdate(final Object entity) {
		getHibernateTemplate().saveOrUpdate(entity);
	}

	public Session getHibernateSession() {
		return this.getSession(true);
	}

	/**
	 * 批量创建对象
	 * 
	 * @param objectsToSave
	 *            List
	 */
	@SuppressWarnings("unchecked")
	public void batchSave(final List<T> objectsToSave) {
		getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				try {
					checkWriteOperationAllowed(getHibernateTemplate(), session);
					if (objectsToSave == null)
						return null;
					int max = objectsToSave.size();
					for (int i = 0; i < max; i++) {
						session.save(objectsToSave.get(i));
						if ((i != 0 && i % DEFAULT_BATCH_SIZE == 0)
								|| i == max - 1) {
							session.flush();
							session.clear();
						}
					}
				} catch (Exception e) {

				}
				return null;
			}
		});

	}

	@SuppressWarnings("unchecked")
	public void batchUpdate(final List objectsToUpdate) {
		getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				checkWriteOperationAllowed(getHibernateTemplate(), session);
				if (objectsToUpdate == null)
					return null;
				int max = objectsToUpdate.size();
				for (int i = 0; i < max; i++) {
					session.merge(objectsToUpdate.get(i));
					// session.update(objectsToUpdate.get(i));
					if ((i != 0 && i % DEFAULT_BATCH_SIZE == 0) || i == max - 1) {
						session.flush();
						session.clear();
					}
				}
				return null;
			}
		});
	}

	@SuppressWarnings("unchecked")
	public void batchSaveOrUpdate(final List objectsToSaveOrUpdate) {
		getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				checkWriteOperationAllowed(getHibernateTemplate(), session);
				if (objectsToSaveOrUpdate == null)
					return null;
				int max = objectsToSaveOrUpdate.size();
				for (int i = 0; i < max; i++) {
					Object obj = objectsToSaveOrUpdate.get(i);
					// session.merge(obj);
					session.saveOrUpdate(obj);
					if ((i != 0 && i % DEFAULT_BATCH_SIZE == 0) || i == max - 1) {
						session.flush();
						session.clear();
					}
				}
				return null;
			}
		});
	}

	@SuppressWarnings("unchecked")
	public void batchRemove(final List objectsToRemove) {
		getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				checkWriteOperationAllowed(getHibernateTemplate(), session);
				if (objectsToRemove == null)
					return null;
				int max = objectsToRemove.size();
				for (int i = 0; i < max; i++) {
					session.refresh(objectsToRemove.get(i));
					session.delete(objectsToRemove.get(i));
					if (i % DEFAULT_BATCH_SIZE == 0) {
						session.flush();
						session.clear();
					}
				}
				return null;
			}
		});
	}

	/**
	 * 批量删除
	 * 
	 * @param c
	 * @param key
	 * @param values
	 */
	@SuppressWarnings("unchecked")
	public void batchRemoveByKey(final Class<?> c, final String key,
			final Object[] values) {
		getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				checkWriteOperationAllowed(getHibernateTemplate(), session);
				String hql = "delete " + c.getSimpleName() + " where " + key
						+ "  in  (:values)";
				Query query = session.createQuery(hql);
				query.setParameterList("values", values).executeUpdate();
				return null;
			}
		});
	}

	protected void checkWriteOperationAllowed(HibernateTemplate template,
			Session session) throws InvalidDataAccessApiUsageException {
		if (template.isCheckWriteOperations()
				&& template.getFlushMode() != HibernateAccessor.FLUSH_EAGER
				&& FlushMode.NEVER.equals(session.getFlushMode())) {
			throw new InvalidDataAccessApiUsageException(
					"Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session "
							+ "into FlushMode.AUTO or remove 'readOnly' marker from transaction definition");
		}
	}

	/**
	 * SQL更新操作
	 * 
	 * @param allEntity
	 *            List
	 */
	@SuppressWarnings("unchecked")
	public boolean runSqlSaveOrUpdate(final String hql)
			throws DataAccessException {
		return (Boolean) getHibernateTemplate().execute(
				new HibernateCallback() {
					@SuppressWarnings("deprecation")
					public Object doInHibernate(Session session)
							throws HibernateException {
						boolean result = false;
						try {
							Connection con = session.connection();
							PreparedStatement stmt = con.prepareStatement(hql
									.toLowerCase());
							int k = stmt.executeUpdate();

							if (k == 0)
								return false;
							return true;
						} catch (Exception e) {
							e.printStackTrace();
						}
						return result;
					}
				});
	}

	/**
	 * SQL查询操作
	 * 
	 * @param allEntity
	 *            List
	 */
	@SuppressWarnings("unchecked")
	public Object runSqlQuery(final String hql) throws DataAccessException {
		return getHibernateTemplate().execute(new HibernateCallback() {
			@SuppressWarnings("deprecation")
			public Object doInHibernate(Session session)
					throws HibernateException {
				ResultSet rs = null;
				try {
					Connection con = session.connection();
					PreparedStatement stmt = con.prepareStatement(hql.toLowerCase());
					rs = stmt.executeQuery();
				} catch (Exception e) {
					// e.printStackTrace();
					// not todo
				}
				return rs; //
			}
		});
	}

	/**
	 * 得到数据库连接
	 * 
	 * @param allEntity
	 *            List
	 */
	@SuppressWarnings("unchecked")
	public Connection getConnection() throws DataAccessException {
		return (Connection) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						Connection con = null;
						try {
							con = session.connection();
						} catch (Exception e) {
						}
						return con;
					}
				});
	}

	/**
	 * update the object of entity
	 * 
	 * @param entity
	 */
	public void merge(final Object entity) {
		getHibernateTemplate().merge(entity);
	}

	public void update(final Object entity) {
		getHibernateTemplate().evict(entity);
		getHibernateTemplate().update(entity);
	}

	public void refresh(final Object entity) {
		this.getSessionFactory().getCurrentSession().clear();
		getHibernateTemplate().refresh(entity);
	}

	/**
	 * delete the object of entity
	 * 
	 * @param entity
	 */
	public void delete(final Object entity) {
		getHibernateTemplate().delete(entity);
	}

	/**
	 * load a Object from DB by id
	 * 
	 * @param entity
	 * @param id
	 * @return Object
	 */

	public Object loadByPriKey(final Class<?> entity, final Serializable id) {
		getHibernateTemplate().setCacheQueries(true);
		return getHibernateTemplate().load(entity, id);
	}

	/**
	 * get a Object from DB by id
	 * 
	 * @param entity
	 * @param id
	 * @return Object
	 */
	public Object getByPk(final Class<?> entity, final Serializable id) {
		getHibernateTemplate().setCacheQueries(true);
		return getHibernateTemplate().get(entity, id);
	}

	/**
	 * 根据条件取得实体类
	 * 
	 * @param entity
	 * @param key
	 * @param value
	 * @return
	 */
	@SuppressWarnings( { "unchecked" })
	public Object getEntityByArgs(final Class entity,
			final Map<String, Serializable> args) {
		return getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				getHibernateTemplate().setCacheQueries(true);
				Criteria c = session.createCriteria(entity);
				if (args == null)
					return null;
				Set<String> keys = args.keySet();
				for (String key : keys) {
					Object value = (Object) args.get(key);
					c.add(Restrictions.eq(key, value));
				}
				return c.list().get(0);
			}
		});
	}

	/**
	 * find all rows from the table
	 * 
	 * @param entity
	 * @return list
	 */
	public List findAll(final Class<?> entity) {
		getHibernateTemplate().setCacheQueries(true);
		return getHibernateTemplate().find("from " + entity.getName());
	}

	public List findByHql(final String hql) {
		getHibernateTemplate().setCacheQueries(true);
		return getHibernateTemplate().find(hql);
	}

	public List findByNamedQuery(final String namedQuery) {
		getHibernateTemplate().setCacheQueries(true);
		return getHibernateTemplate().findByNamedQuery(namedQuery);
	}

	public List findByNamedQuery(final String query, final Object parameter) {
		getHibernateTemplate().setCacheQueries(true);
		return getHibernateTemplate().findByNamedQuery(query, parameter);
	}

	public List findByNamedQuery(final String query, final Object[] parameters) {
		getHibernateTemplate().setCacheQueries(true);
		return getHibernateTemplate().findByNamedQuery(query, parameters);
	}

	public List find(final String query) {
		getHibernateTemplate().setCacheQueries(true);
		return getHibernateTemplate().find(query);
	}

	/**
	 * 取记录总数
	 * 
	 * @return int
	 */
	public int getCount(String queryString) {
		int count = 0;
		getHibernateTemplate().setCacheQueries(true);
		count = ((Long) getHibernateTemplate().iterate(queryString).next())
				.intValue();
		return count;
	}

	@SuppressWarnings("unchecked")
	public List<T> find(final String query, final Object parameter) {
		getHibernateTemplate().setCacheQueries(true);
		return getHibernateTemplate().find(query, parameter);
	}

	@SuppressWarnings( { "unchecked" })
	public List<T> findByCriteria(final DetachedCriteria detachedCriteria,
			final int pageIndex, final int pageSize) {
		return (List<T>) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						getHibernateTemplate().setCacheQueries(true);
						// Criteria criteria = detachedCriteria
						// .getExecutableCriteria(session);
						if (pageSize > 0)
							return getHibernateTemplate().findByCriteria(
									detachedCriteria, pageIndex, pageSize);
						else
							return getHibernateTemplate().findByCriteria(
									detachedCriteria);
					}
				});
	}

	@SuppressWarnings( { "unchecked" })
	public int getCountByCriteria(final DetachedCriteria detachedCriteria) {
		Integer count = (Integer) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						getHibernateTemplate().setCacheQueries(true);
						Criteria criteria = detachedCriteria
								.getExecutableCriteria(session);
						return ((Long)criteria.setProjection(Projections.rowCount())
								.uniqueResult()).intValue();
					}
				});
		return count.intValue();
	}

	public Object loadByKey(Class entity, String keyName, Object keyValue)
			throws DataAccessException {
		getHibernateTemplate().setCacheQueries(true);
		List result = getHibernateTemplate().find(
				"from " + entity.getName() + " where " + keyName + " = ?",
				keyValue);
		if (result != null && result.size() > 0) {
			return result.get(0);
		} else {
			return null;
		}

	}

	@SuppressWarnings( { "unchecked", "deprecation" })
	public Criteria getCriteria(final Class entity) {
		return (Criteria) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						getHibernateTemplate().setCacheQueries(true);
						Criteria criteria = session.createCriteria(entity);
						return criteria;
					}
				});

	}

	@SuppressWarnings( { "unchecked" })
	public Criteria getCriteriaByDetachedCriteria(
			final DetachedCriteria detachedCriteria) {

		return (Criteria) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						getHibernateTemplate().setCacheQueries(true);
						Criteria criteria = detachedCriteria
								.getExecutableCriteria(session);
						return criteria;
					}
				});

	}

	// ==========================================================

	/**
	 * 获取前几个数据
	 */
	public List getLimit(final int count, final String hql) {
		return getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session s) throws HibernateException {
				getHibernateTemplate().setCacheQueries(true);
				Query query = s.createQuery(hql);
				query.setFirstResult(0);
				query.setMaxResults(count);
				List list = query.list();
				return list;
			}
		});
	}

	public List getFetchSize(final int count, final String hql) {
		return getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session s) throws HibernateException {
				getHibernateTemplate().setCacheQueries(true);
				Query query = s.createQuery(hql);
				query.setFetchSize(count);
				List list = query.list();
				return list;
			}
		});
	}

	/**
	 * 分页返回查询结果，如果分页不正确，则不能返回数据。
	 * 
	 * @param startRs
	 *            ，开始页，第一页为0
	 * @param perPage
	 *            ，每页显示的条目数。
	 * @param hql
	 *            ，查询语句
	 * @return 返回列表 List
	 */
	public List getPageList(final int startRs, final int perPage,
			final String hql) {
		return getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session s) throws HibernateException {
				getHibernateTemplate().setCacheQueries(true);
				Query query = s.createQuery(hql);
				query.setFirstResult(startRs);
				query.setMaxResults(perPage);
				List list = query.list();
				return list;

			}
		});
	}

	public List getPageList(final int startRs, final int perPage,
			final String hql, final Date startDate) {
		return getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session s) throws HibernateException {
				getHibernateTemplate().setCacheQueries(true);
				Query query = s.createQuery(hql);
				query.setFirstResult(startRs);
				query.setMaxResults(perPage);
				query.setDate("startDate", startDate);
				List list = query.list();
				return list;
			}
		});
	}

	public List getTotal(final String hql, final Date startDate) {
		return getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session s) throws HibernateException {
				getHibernateTemplate().setCacheQueries(true);
				Query query = s.createQuery(hql);
				query.setDate("startDate", startDate);
				List list = query.list();
				return list;
			}
		});
	}

	/**
	 * 通过开始时间和结束时间得到数据总和
	 * 
	 * @param hql
	 * @param startDateConditions
	 *            开始时间条件，即pojo的字段
	 * @param startDate
	 *            开始时间的值
	 * @param endDateConditions
	 *            结束时间条件
	 * @param endDate
	 *            结束时间值
	 * @return
	 */
	public List getBetweenTimeTotalCount(final String hql,
			final String startDateConditions, final Date startDate,
			final String endDateConditions, final Date endDate) {
		return getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session s) throws HibernateException {
				getHibernateTemplate().setCacheQueries(true);
				Query query = s.createQuery(hql);
				query.setTimestamp(startDateConditions, startDate);
				query.setTimestamp(endDateConditions, endDate);
				List list = query.list();
				return list;
			}
		});
	}

	/**
	 * 根据指定翻页器返回list结果集
	 * 
	 * @param page
	 *            翻页器
	 * @return 指定翻页后的结果集
	 */
	public List getPageListByTime(final int startRs, final int perPage,
			final String hql, final Timestamp beginTime, final Timestamp endTime) {
		return getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session s) throws HibernateException {
				getHibernateTemplate().setCacheQueries(true);
				Query query = s.createQuery(hql);
				query.setFirstResult(startRs);
				query.setMaxResults(perPage);
				query.setTimestamp("beginTime", beginTime);
				query.setTimestamp("endTime", endTime);
				List list = query.list();
				return list;
			}
		});
	}

	/**
	 * 执行HQL语句进行创建或更新或删除
	 * 
	 * @param hql
	 *            String
	 * @return int
	 */
	@SuppressWarnings("unchecked")
	public int runHql(final String hql) {
		try {
			this.getHibernateTemplate().execute(new HibernateCallback() {
				public Object doInHibernate(Session s)
						throws HibernateException, SQLException {
					getHibernateTemplate().setCacheQueries(true);
					s.createQuery(hql).executeUpdate();
					return null;
				}
			});
			return 1;
		} catch (DataAccessException dae) {
			logger.error("执行HQL出错:", dae);
			return 0;
		}
	}

	/**
	 * 执行HQL查询,使用格式 from Object a where a.id:id
	 * 
	 * @param queryString
	 * @param parameters
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<T> findByQuery(final String queryString, final String[] fields,
			final Object[] parameters) {
		return (List<T>) getHibernateTemplate().execute(
				new HibernateCallback() {
					public List<T> doInHibernate(Session session) {
						Query query = session.createQuery(queryString);
						if (parameters != null) {
							for (int i = 0; i < parameters.length; i++) {
								for (int j = 0; j < fields.length; j++) {
									query
											.setParameter(fields[j],
													parameters[i]);
								}
							}
						}
						// query.executeUpdate();
						return query.list();
					}
				});
	}

	public List findTop(final String queryString, final Object[] parameters,
			int n) {
		HibernateTemplate template = getHibernateTemplate();
		template.setMaxResults(n);
		List list = template.find(queryString, parameters);
		template.setMaxResults(0);
		return list;
	}

	public List findPageByQuery(final String queryString,
			final Object[] parameters, final Page page) {
		return (List) getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws SQLException, HibernateException {
						Query query = session.createQuery(queryString);
						if (parameters != null) {
							for (int i = 0; i < parameters.length; i++) {
								query.setParameter(i, parameters[i]);
							}
						}
						query.setFirstResult(page.getStart());
						query.setMaxResults(page.getPageSize());
						return query.list();
					}
				});
	}
	
}
